package com.guojiang.guopicturebackend.service.impl;


import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guojiang.guopicturebackend.exception.BusinessException;
import com.guojiang.guopicturebackend.exception.ErrorCode;
import com.guojiang.guopicturebackend.exception.ThrowUtils;
import com.guojiang.guopicturebackend.mapper.SpaceMapper;
import com.guojiang.guopicturebackend.model.dto.space.analyze.*;
import com.guojiang.guopicturebackend.model.entity.Picture;
import com.guojiang.guopicturebackend.model.entity.Space;
import com.guojiang.guopicturebackend.model.entity.User;
import com.guojiang.guopicturebackend.model.vo.space.analyze.*;
import com.guojiang.guopicturebackend.service.PictureService;
import com.guojiang.guopicturebackend.service.SpaceAnalyzeService;
import com.guojiang.guopicturebackend.service.SpaceService;
import com.guojiang.guopicturebackend.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 过江辉
 * @description 针对表【space(空间)】的数据分析操作Service实现
 * @createDate 2025-01-20 02:16:26
 */
@Service
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space>
        implements SpaceAnalyzeService {

    @Resource
    private UserService userService;

    @Resource
    private SpaceService spaceService;

    @Resource
    private PictureService pictureService;

    /**
     * 获取空间使用情况分析
     *
     * @param spaceUsageAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        // 1. 区分所查空间，先校验一遍权限
        checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);
        // 2. 公共空间或全部空间需要查询图片表，特定空间只需查询空间表
        boolean queryPublic = spaceUsageAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceUsageAnalyzeRequest.isQueryAll();
        if (queryPublic || queryAll) {
            // 统计使用情况
            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            // 只查询 picSize 字段
            queryWrapper.select("picSize");
            // 补充查询范围
            fillAnalyzeQueryRequest(spaceUsageAnalyzeRequest, queryWrapper);
            List<Object> picSizeObjList = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = picSizeObjList.stream().mapToLong(obj -> (Long) obj).sum();
            long usedCount = picSizeObjList.size();
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(usedSize);
            spaceUsageAnalyzeResponse.setUsedCount(usedCount);
            spaceUsageAnalyzeResponse.setMaxSize(null);
            spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
            spaceUsageAnalyzeResponse.setMaxCount(null);
            spaceUsageAnalyzeResponse.setCountUsageRatio(null);
            // 3. 返回结果
            return spaceUsageAnalyzeResponse;
        } else {
            Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR, "空间ID非法");
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "查询的空间不存在");
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(space.getTotalSize());
            spaceUsageAnalyzeResponse.setUsedCount(space.getTotalCount());
            spaceUsageAnalyzeResponse.setMaxSize(space.getMaxSize());
            double sizeUsageRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
            spaceUsageAnalyzeResponse.setSizeUsageRatio(sizeUsageRatio);
            spaceUsageAnalyzeResponse.setMaxCount(space.getMaxCount());
            double countUsageRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
            spaceUsageAnalyzeResponse.setCountUsageRatio(countUsageRatio);
            // 3. 返回结果
            return spaceUsageAnalyzeResponse;
        }
    }

    /**
     * 获取空间内图片分类情况分析
     *
     * @param spaceCategoryAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, User loginUser) {
        // 1. 区分所查空间，先校验一遍权限
        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest, loginUser);
        // 2. 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 补充查询字段
        fillAnalyzeQueryRequest(spaceCategoryAnalyzeRequest, queryWrapper);
        // 使用 MyBatis Plus 分组查询语法
        // 查询分类、总数、总大小，按照分类分组计算
        queryWrapper.select("category", "COUNT(*) AS count", "SUM(picSize) AS totalSize")
                .groupBy("category");
        // 3. 返回分类查询结果列表
        return pictureService.getBaseMapper().selectMaps(queryWrapper)
                .stream()
                .map(result -> {
                    String category = (String) result.get("category");
                    if (category == null || StrUtil.isBlank(category)) {
                        category = "无分类";
                    }
                    Long count = ((Number) result.get("count")).longValue();
                    Long totalSize = ((Number) result.get("totalSize")).longValue();
                    return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
                }).collect(Collectors.toList());
    }

    /**
     * 获取空间内标签情况分析
     *
     * @param spaceTagAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, User loginUser) {
        // 1. 区分所查空间，先校验一遍权限
        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest, loginUser);
        // 2. 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 补充查询字段
        fillAnalyzeQueryRequest(spaceTagAnalyzeRequest, queryWrapper);
        // 使用 MyBatis Plus 分组查询语法
        queryWrapper.select("tags");
        List<Object> tagsJsonObjList = pictureService.getBaseMapper().selectObjs(queryWrapper);
        List<String> tagsJsonList = tagsJsonObjList.stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());
        // 解析标签并统计
        // ["Java", "编程", "知识分享"], ["羽毛球", "运动", "热血"] 
        // 扁平化处理==> "Java", "编程", "知识分享", "羽毛球", "运动", "热血"
        // 再根据不同标签分组求和得到 Map
        Map<String, Long> tagCountMap = tagsJsonList.stream().flatMap(tagsJson -> JSONUtil.toList(tagsJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        // 转化为响应对象，按照使用次数排序
        return tagCountMap.entrySet().stream()
                .sorted(Comparator.comparingLong(Map.Entry::getValue))
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 获取空间内图片大小的分段分析
     *
     * @param spaceSizeAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, User loginUser) {
        // 1. 区分所查空间，先校验一遍权限
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest, loginUser);
        // 2. 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 补充查询字段
        fillAnalyzeQueryRequest(spaceSizeAnalyzeRequest, queryWrapper);
        // 使用 MyBatis Plus 分组查询语法
        // 查询所以符合大小要求的图片
        queryWrapper.select("picSize");
        List<Long> picSizeObjList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(size -> (Long) size)
                .collect(Collectors.toList());
        // 定义图片大小分组范围
        LinkedHashMap<String, Long> sizeRangeMap = new LinkedHashMap<>();
        long count = picSizeObjList.stream().filter(size -> size < 100 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("< 100 KB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 100 * 1024 && size < 300 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("100 KB - 300 KB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 300 * 1024 && size < 600 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("300KB - 600KB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 600 * 1024 && size < 1 * 1024 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("600 KB - 1 MB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 1 * 1024 * 1024 && size < 2 * 1024 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("1 MB - 2 MB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 2 * 1024 * 1024 && size < 4 * 1024 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("2 MB - 4 MB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 4 * 1024 * 1024 && size < 8 * 1024 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("4 MB - 8 MB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 8 * 1024 * 1024 && size < 12 * 1024 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("8 MB - 12 MB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 12 * 1024 * 1024 && size < 16 * 1024 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("12 MB - 16 MB", count);
        }
        count = picSizeObjList.stream().filter(size -> size >= 16 * 1024 * 1024 && size <= 20 * 1024 * 1024).count();
        if (count > 0) {
            sizeRangeMap.put("16 MB - 20 MB", count);
        }
        // 转换为响应对象
        return sizeRangeMap.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 用户上传图片行为分析
     *
     * @param spaceUserAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, User loginUser) {
        // 1. 区分所查空间，先校验一遍权限
        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest, loginUser);
        // 2. 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 补充查询字段
        fillAnalyzeQueryRequest(spaceUserAnalyzeRequest, queryWrapper);
        // 如果是查询单个用户，校验成功后，补充用户ID查询
        Long userId = spaceUserAnalyzeRequest.getUserId();
        // 用户可以为空，不查询单个用户，但是输入不能非法
        if(userId != null) {
            ThrowUtils.throwIf(userId <= 0 , ErrorCode.PARAMS_ERROR, "输入的用户ID非法");
            User user = userService.getById(userId);
            ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR, "该用户不存在");
        }
        queryWrapper.eq(userId != null && userId > 0, "userId", userId);
        // 补充时间分析维度：每日、每周、每月、每年
        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
        switch (timeDimension) {
            case "day":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m-%d') AS period", "COUNT(*) AS count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(createTime) AS period", "COUNT(*) AS count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m') AS period", "COUNT(*) AS count");
                break;
            case "year":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y') AS period", "COUNT(*) AS count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数非法");
        }
        // 分组排序
        queryWrapper.groupBy("period").orderByAsc("period");
        // 查询并封装结果
        List<Map<String, Object>> queryResult = pictureService.getBaseMapper().selectMaps(queryWrapper);
        return queryResult
                .stream()
                .map(result -> {
                    String period;
                    if (result.get("period") == null) {
                        period = "未知时段";
                    } else {
                        period = result.get("period").toString();
                    }
                    Long count;
                    if (result.get("count") == null) {
                        long flag = 0;
                        count = flag;
                    } else {
                        count = ((Number) result.get("count")).longValue();
                    }
                    return new SpaceUserAnalyzeResponse(period, count);
                })
                .collect(Collectors.toList());
    }

    /**
     * 空间使用排行分析（默认取前十，仅管理员可用）
     *
     * @param spaceRankAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, User loginUser) {
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "spaceName", "userId", "totalSize")
                .orderByDesc("totalSize") // 降序排序
                .last("limit " + spaceRankAnalyzeRequest.getTopN()); // 取前 N 名
        // 查询封装结果
        return spaceService.list(queryWrapper);
    }

    private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest, User loginUser) {
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();
        // 仅管理员有权分析全空间或公共空间
        if (queryAll || queryPublic) {
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "无权进行此操作");
        } else {
            // 如果是分析特定空间
            // 仅本人和管理员可以进行
            Long spaceId = spaceAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR, "请求分析空间参数非法");
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "要分析的空间不存在");
            spaceService.checkSpaceAuth(space, loginUser);
        }
    }

    /**
     * 根据请求对象封装查询条件
     *
     * @param spaceAnalyzeRequest
     * @param queryWrapper
     */
    private void fillAnalyzeQueryRequest(SpaceAnalyzeRequest spaceAnalyzeRequest, QueryWrapper<Picture> queryWrapper) {
        // 查询全空间，不需要拼接条件,，直接返回
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();
        if (queryAll) {
            return;
        }
        // 公共图库
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        if (queryPublic) {
            queryWrapper.isNull("spaceId");
            return;
        }
        // 非公共空间
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        if (spaceId != null) {
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");
    }
}




